package com.scs.application.modules.wm.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.exception.ValidException;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrHis;
import com.scs.application.modules.base.mapper.DeptMapper;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.service.MatrHisService;
import com.scs.application.modules.sys.properties.SystemProperties;
import com.scs.application.modules.thirdparty.dto.his.*;
import com.scs.application.modules.thirdparty.request.convert.his.zhonglian.dto.HisStockQueryZhongLian;
import com.scs.application.modules.thirdparty.request.convert.his.zhonglian.dto.HisStockResultZhongLian;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.mapper.StockDeptBillItemMapper;
import com.scs.application.modules.wm.mapper.StockDeptMapper;
import com.scs.application.modules.wm.service.StockDeptBilltemService;
import com.scs.application.modules.wm.service.StockDeptLockLogHistoryService;
import com.scs.application.modules.wm.service.StockDeptLockLogService;
import com.scs.application.modules.wm.service.StockDeptService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 科室三级库 服务实现类
 * </p>
 */
@Service
public class StockDeptServiceImpl extends BaseServiceImpl<StockDeptMapper, StockDept> implements StockDeptService {
    @Autowired
    private MatrMapper mapper;
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private StockDeptLockLogService stockDeptLockLogService;
    @Autowired
    private StockDeptLockLogHistoryService stockDeptLockLogHistoryService;
    @Autowired
    private StockDeptBilltemService stockDeptBIllItemService;
    @Autowired
    private StockDeptBillItemMapper stockDeptBillItemMapper;
    @Autowired
    @Lazy
    private MatrHisService matrHisService;


    @Autowired
    private SystemProperties systemProperties;

    /**
     * @description: 查询库存列表
     * @author: Tai
     * @date: 2024/10/22 09:55
     **/
    @Override
    public List<HislowQueryResult> listWithHisCodeAndHrpCode(HislowQuery query, boolean flagGt0) {
        List<Matr> matrList = mapper.selectList(
                Wrappers.<Matr>query()
                        .eq(StringUtils.isNotBlank(query.getHisCode()),"ifnull(his_code,'')",query.getHisCode())
        );
        BusinessException.throwValidFailIf(ObjectUtil.length(matrList)==0,"未找到相关商品,HIS编码[%s]",query.getHisCode());
        QueryWrapper<StockDept> wrapper = Wrappers.<StockDept>query();
        String msg= "根据相关商品";
        if (StringUtils.isNotBlank(query.getDeptCodeStock())) {
            List<Dept> deptList = deptMapper.selectList(Wrappers.<Dept>query().eq("his_code", query.getDeptCodeStock()));
            BusinessException.throwValidFailIf(ObjectUtil.length(deptList)==0,"未找到相关科室,科室编码[%s]",query.getDeptCodeStock());
            BusinessException.throwValidFailIf(ObjectUtil.length(deptList)>1,"找到多个，请联系运营人员检查,科室编码[%s]",query.getDeptCodeStock());
            wrapper.eq("dept_id", deptList.get(0).getId());
            msg+=",相关科室";
        }
        if (flagGt0){
            wrapper.gt("qty", 0);
            msg+=",可用数量大于0";
        }
        wrapper.in("matr_id", matrList.stream().map(Matr::getId).collect(Collectors.toList()));
        List<StockDept> StockDeptList = baseMapper.listWithQty(wrapper);
        BusinessException.throwValidFailIf(ObjectUtil.length(StockDeptList)==0,"未找到可用库存,%s",msg);
        Map<String,Matr> matyById = matrList.stream().collect(Collectors.toMap(item -> item.getId(), item -> item));
        List<HislowQueryResult> hislowQueryResultList = new ArrayList<>();
        HislowQueryResult result;
        for(StockDept stockDept : StockDeptList) {
            result = new HislowQueryResult();
            BeanUtils.copyProperties(stockDept,result);
            result.setQty(stockDept.getQtyReal());
            result.setHisCode(matyById.get(stockDept.getMatrId()).getHisCode());
            result.setMatrCode(matyById.get(stockDept.getMatrId()).getHrpCode());
            hislowQueryResultList.add(result);
        }
        return hislowQueryResultList;
    }
    /**
     * @description: 查询库存列表
     * @author: Tai
     * @date: 2024/10/22 09:55
     **/
    @Override
    public List<HisStockResultZhongLian> listBatchByHisIdForZl(List<HisStockQueryZhongLian> queryList) {
        List<String> feeItemIdList = queryList.stream().map(HisStockQueryZhongLian::getEisaiItemId).distinct().collect(Collectors.toList());

        List<MatrHis> matrHisList = matrHisService.list(Wrappers.<MatrHis>query().in("his_id",feeItemIdList));

        if (ObjectUtil.length(matrHisList) != feeItemIdList.size()) {
            List<String> hisIdList = matrHisList.stream().filter(find -> StringUtils.isNotBlank(find.getHisId())).map(MatrHis::getHisId).collect(Collectors.toList());
            feeItemIdList.stream().filter(uk -> !hisIdList.contains(uk) ).findAny().ifPresent(snFind -> {
                throw new ValidException(StrUtil.format("未找到计费项目,收费项目标识[{}]",snFind));
            });
        }


        List<String> hisCodeList = matrHisList.stream().filter(find -> StringUtils.isNotBlank(find.getHisCode())).map(MatrHis::getHisCode).collect(Collectors.toList());
        List<Matr> matrList = mapper.selectList(Wrappers.<Matr>query().in("ifnull(his_code,'')", hisCodeList));

        if (matrList.isEmpty()) {
            throw new ValidException(StrUtil.format("未找到计费耗材,收费项目标识[{}]",feeItemIdList.get(0)));
        }

        List<String> matrHisCode = matrList.stream().map(Matr::getHisCode).distinct().collect(Collectors.toList());
        if (ObjectUtil.length(matrHisCode) != matrHisList.size()) {
            List<String> hisIdList = matrHisList.stream().filter(find -> StringUtils.isNotBlank(find.getHisId())).map(MatrHis::getHisId).collect(Collectors.toList());
            feeItemIdList.stream().filter(uk -> !hisIdList.contains(uk) ).findAny().ifPresent(snFind -> {
                throw new ValidException(StrUtil.format("未找到计费耗材,收费项目标识[{}]",snFind));
            });
        }

        List<String> deptHisIdList = queryList.stream().map(HisStockQueryZhongLian::getEisaiItemStoreId).distinct().collect(Collectors.toList());

        List<Dept> deptList = deptMapper.selectList(Wrappers.<Dept>query().in("his_id", deptHisIdList));

        List<String> deptHisIdListDb = deptList.stream().map(Dept::getHisId).distinct().collect(Collectors.toList());

        if (ObjectUtil.length(deptHisIdList) != deptHisIdListDb.size()) {
            deptHisIdList.stream().filter(uk -> !deptHisIdListDb.contains(uk) ).findAny().ifPresent(snFind -> {
                throw new ValidException(StrUtil.format("未找到相关科室,科室标识[{}]",snFind));
            });
        }


        List<String> deptIdList = deptList.stream().map(Dept::getId).distinct().collect(Collectors.toList());

        QueryWrapper<StockDept> wrapper = Wrappers.<StockDept>query();
        wrapper.in("dept_id", deptIdList).gt("qty", 0);
        wrapper.in("matr_id", matrList.stream().map(Matr::getId).collect(Collectors.toList()));
        List<StockDept> StockDeptList = baseMapper.listWithQty(wrapper);

        if (ObjectUtil.length(StockDeptList)  == 0 ) {
            throw new ValidException(StrUtil.format("未找到可用库存,科室标识[{}],收费项目标识[{}]",deptList.get(0).getHisId(),matrHisList.get(0).getHisId()));
        }

        List<String> stockDeptHisIdAndFeeHisId = StockDeptList.stream().map(tmp -> tmp.getDeptHisId() + tmp.getFeeHisId()).collect(Collectors.toList());
        queryList.stream().filter(tmp -> !stockDeptHisIdAndFeeHisId.contains(tmp.getEisaiItemStoreId() + tmp.getEisaiItemId()) ).findAny().ifPresent(snFind -> {
            throw new ValidException(StrUtil.format("未找到可用库存,科室标识[{}],收费项目标识[{}]",snFind.getEisaiItemStoreId(),snFind.getEisaiItemId()));
        });

        Map<String,Matr> matyById = matrList.stream().collect(Collectors.toMap(item -> item.getId(), item -> item));
        Map<String,Dept> deptById = deptList.stream().collect(Collectors.toMap(item -> item.getId(), item -> item));
        List<HisStockResultZhongLian> resultZhongLianList = new ArrayList<>();
        HisStockResultZhongLian resultOne;
        for(StockDept stock : StockDeptList) {
            resultOne = new HisStockResultZhongLian();
            // 材料id
            resultOne.setEisaiItemId(stock.getMatrId());
            // 材料规格
            resultOne.setEisaiItemName(stock.getMatrSpec());
            // 产地
            resultOne.setEisaiItemDprentpName(matyById.get(stock.getMatrId()).getMfgName());
            // 成本价
            resultOne.setEisaiItemCostPrice(matyById.get(stock.getMatrId()).getSkuPrice());
            // 零售价
            resultOne.setEisaiItemSalesPrice(matyById.get(stock.getMatrId()).getSkuPrice());
            // 库房id
            resultOne.setEisaiItemStoreId(deptById.get(stock.getDeptId()).getHisId());
            // 库存量
            resultOne.setEisaiItemStoreQunt(stock.getSkuQty());
            // 条码
            resultOne.setEisaiBarcode(null);
            resultZhongLianList.add(resultOne);
        }

        return resultZhongLianList;
    }




    /**
     * @description: 计费或者退费 中联
     * @author: Tai
     * @date: 2024/10/22 09:55
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void billBatchByHisIdForZl(HisHighBillBatch query,Boolean isReturn) {
        List<String> matrHisCodeList = query.getDataArr().stream().map(HisHighBillBatchDtl::getHisCode).distinct().collect(Collectors.toList());
        List<Matr> matrList = mapper.selectList(
                Wrappers.<Matr>query()
                        .in(ObjectUtil.length(matrHisCodeList) > 0,"ifnull(his_code,'')",matrHisCodeList)
        );

        if (matrList.isEmpty()) {
            throw new ValidException(StrUtil.format("未找到计费耗材,收费项目标识[{}]",query.getDataArr().get(0).getFeeItemId()));
        }

        // 消耗科室信息
        List<String> deptCodeUseList = query.getDataArr().stream().map(HisHighBillBatchDtl::getDeptCodeUse).distinct().collect(Collectors.toList());
        List<Dept> deptList = deptMapper.selectList(Wrappers.<Dept>query().in("his_code", deptCodeUseList));
        BusinessException.throwValidFailIf(ObjectUtil.length(deptList)==0,"未找到相关科室信息，请联系运营人员检查");
        BusinessException.throwValidFailIf(deptList.size() != deptCodeUseList.size(),"科室信息缺失，请联系运营人员检查");
        Map<String,Dept> deptByHisCode = deptList.stream().collect(Collectors.toMap(item -> item.getHisCode(), item -> item));


        List<String> matrIdList = matrList.stream().map(Matr::getId).collect(Collectors.toList());
        QueryWrapper<StockDept> wrapper = Wrappers.<StockDept>query();
        List<String> deptIdList = deptList.stream().map(Dept::getId).distinct().collect(Collectors.toList());
        wrapper.in("dept_id", deptIdList).gt("qty", 0);
        wrapper.in("matr_id", matrIdList);
        List<StockDept> stockDeptList = baseMapper.listWithQty(wrapper);
        if (ObjectUtil.length(stockDeptList)  == 0 ) {
            throw new ValidException(StrUtil.format("未找到可用库存,科室标识[{}],收费项目标识[{}]",deptList.get(0).getHisId(),query.getDataArr().get(0).getFeeItemId()));
        }

        List<String> stockDeptHisIdAndFeeHisId = stockDeptList.stream().map(tmp -> tmp.getDeptHisId() + tmp.getFeeHisId()).collect(Collectors.toList());
        query.getDataArr().stream().filter(tmp -> !stockDeptHisIdAndFeeHisId.contains(tmp.getDeptIdUse() + tmp.getFeeItemId()) ).findAny().ifPresent(snFind -> {
            throw new ValidException(StrUtil.format("未找到可用库存,科室标识[{}],收费项目标识[{}]",snFind.getDeptIdUse(),snFind.getFeeItemId()));
        });

        Map<String,List<StockDept>> stockDeptByDeptId = stockDeptList.stream().collect(Collectors.groupingBy(item -> item.getDeptId()));

        List<StockDept> stockDeptFindList;
        List<String> stockIdChange = new ArrayList<>();
        Dept deptUse ;

        List<StockDeptBillItem> billItemList= new ArrayList<>();
        StockDeptBillItem billItem;

        // 退费校验
        Map<String,List<StockDeptBillItem>> billGroupDeptUseDbFind = null;
        if (isReturn) {
            QueryWrapper<StockDeptBillItem> queryWrapper = Wrappers.<StockDeptBillItem>query();
            queryWrapper.and(wrapper2 -> wrapper2.in("dept_code_use",deptCodeUseList).in("matr_id",matrIdList));
            billGroupDeptUseDbFind = stockDeptBillItemMapper.canReturnList(queryWrapper)
                    .stream().collect(Collectors.groupingBy(StockDeptBillItem::getDeptCodeUse));
            final  Map<String,List<StockDeptBillItem>> billGroupDeptUseDb = billGroupDeptUseDbFind;
            if (billGroupDeptUseDb == null || billGroupDeptUseDb.isEmpty()) {
                throw new ValidException(StrUtil.format("无法退费因为未找到计费信息,科室标识[{}],收费项目标识[{}]",deptList.get(0).getHisId(),query.getDataArr().get(0).getFeeItemId()));
            }
            Map<String,List<HisHighBillBatchDtl>> toBillGroupDeptUse = query.getDataArr().stream().collect(Collectors.groupingBy(HisHighBillBatchDtl::getDeptCodeUse));

            toBillGroupDeptUse.keySet().forEach(deptCodeUse -> {
                if (!billGroupDeptUseDb.containsKey(deptCodeUse)) {
                    throw new ValidException(
                            StrUtil.format(
                            "无法退费因为未找到计费信息,科室标识[{}],收费项目标识[{}]",deptByHisCode.get(deptCodeUse).getHisId()
                            ,query.getDataArr().get(0).getFeeItemId()
                            )
                    );
                }
                Map<String,List<HisHighBillBatchDtl>> toBillGroupFeeItemId = toBillGroupDeptUse.get(deptCodeUse)
                        .stream().collect(Collectors.groupingBy(HisHighBillBatchDtl::getFeeItemId));

                Map<String,List<StockDeptBillItem>> billGroupFeeItemIdDb = billGroupDeptUseDb.get(deptCodeUse)
                        .stream().collect(Collectors.groupingBy(StockDeptBillItem::getFeeItemId));
                toBillGroupFeeItemId.keySet().forEach(feeItemId -> {
                    if (!billGroupFeeItemIdDb.containsKey(feeItemId)) {
                        throw new ValidException(
                                StrUtil.format(
                                        "无法退费因为未找到计费信息,科室标识[{}],收费项目标识[{}]",deptByHisCode.get(deptCodeUse).getHisId()
                                        ,feeItemId
                                )
                        );
                    }
                    Double qtyReturn = toBillGroupFeeItemId.get(feeItemId).stream().mapToDouble(HisHighBillBatchDtl::getFeeCount).sum();
                    Double qtyBill = billGroupFeeItemIdDb.get(feeItemId).stream().mapToDouble(StockDeptBillItem::getQty).sum();
                    if (qtyReturn > qtyBill) {
                        throw new ValidException(
                                StrUtil.format(
                                        "无法退费因为已超过累计计费数量,科室标识[{}],收费项目标识[{}],累计计费[{}],本次退费[{}]",deptByHisCode.get(deptCodeUse).getHisId()
                                        ,feeItemId,qtyBill,qtyReturn
                                )
                        );
                    }
                });

            });
        }

        Double qtySum = 0d,feeCountLessAll = 0d,feeCountLessOne = 0d;
        for(HisHighBillBatchDtl dtl : query.getDataArr()) {
            deptUse = deptByHisCode.get(dtl.getDeptCodeUse());
            if (stockDeptByDeptId.get(deptUse.getId()) == null) {
                BusinessException.throwValidFail("未找到该科室相关库存,科室名称[%s]",deptUse.getName());
            }
            stockDeptFindList = stockDeptByDeptId.get(deptUse.getId()).stream().filter(tmp -> tmp.getHisCode().equals(dtl.getHisCode())).collect(Collectors.toList());
            if (ObjectUtil.length(stockDeptFindList) == 0 ) {
                BusinessException.throwValidFail("未找到相关库存,收费编码[%s]",dtl.getHisCode());
            }

            if (isReturn) { // 退费
                // 找到最近一次的计费库存
                StockDeptBillItem billTop = billGroupDeptUseDbFind.get(dtl.getDeptCodeUse()).get(0);
                stockDeptFindList = stockDeptFindList.stream().filter(find -> find.getId().equals(billTop.getStockId())).collect(Collectors.toList());
                if (stockDeptFindList.isEmpty()) {
                    stockDeptFindList = stockDeptByDeptId.get(deptUse.getId()).stream().filter(tmp -> tmp.getHisCode().equals(dtl.getHisCode())).collect(Collectors.toList());
                }
            } else{ //计费
                qtySum = stockDeptFindList.stream().mapToDouble(StockDept::getQty).sum();

                if (qtySum < dtl.getFeeCount()) {
                    BusinessException.throwValidFail("该科室该三级库库存不足，科室名称[%s], 收费编码[%s],可用数量[%s],需计费数量{%s}",
                            deptUse.getName(),
                            dtl.getHisCode(),
                            qtySum,
                            dtl.getFeeCount()
                    );
                }
            }


            // 剩余待减去的计费数量
            feeCountLessAll = dtl.getFeeCount();
            for(StockDept stockFind : stockDeptFindList) {
                if (feeCountLessAll <=0) {
                    break;
                }

                if (isReturn) { // 退费
                    stockFind.setSkuQty(stockFind.getSkuQty() + feeCountLessAll);
                    feeCountLessOne = feeCountLessAll;
                    feeCountLessAll = 0d;
                } else{ //计费
                    // 减完小于等于0
                    if (feeCountLessAll > stockFind.getQty()) {
                        feeCountLessOne = stockFind.getQty();
                    } else{
                        feeCountLessOne = feeCountLessAll;
                    }
                    feeCountLessAll = feeCountLessAll - feeCountLessOne;
                    stockFind.setSkuQty(stockFind.getSkuQty() - feeCountLessOne);
                }

                stockIdChange.add(stockFind.getId());

                // 计费明细
                billItem = new StockDeptBillItem();
                BeanUtils.copyProperties(dtl, billItem);
                billItem.setMatrId(stockFind.getMatrId()).setStockId(stockFind.getId());
                billItem.setQty(feeCountLessOne);
                billItem.setFeeItemId(dtl.getFeeItemId());
                billItemList.add(billItem);
            }
        }

        //1 更新库存信息
        List<StockDept> stockChange = stockDeptList.stream().filter(item -> stockIdChange.contains(item.getId())).collect(Collectors.toList());
        if (ObjectUtil.length(stockChange) > 0) {
            this.updateBatchById(stockChange);
        }

        //3 计费明细
        stockDeptBIllItemService.saveBatch(billItemList);
    }


    /**
     * @description: 锁定库存
     * @author: Tai
     * @date: 2024/10/22 09:55
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void lock(HislowLock query) {
        List<String> matrCodeList = query.getDataArr().stream().map(HislowLockDtl::getMatrCode).distinct().collect(Collectors.toList());
        List<Matr> matrList = mapper.selectList(
                Wrappers.<Matr>query()
                        .in(ObjectUtil.length(matrCodeList) > 0,"ifnull(hrp_code,'')",matrCodeList)
        );
        BusinessException.throwValidFailIf(ObjectUtil.length(matrList)==0,"未找到相关商品");
        Map<String,Matr> matrMapByHrpCode = matrList.stream().collect(Collectors.toMap(item -> item.getHrpCode(), item -> item));

        // 锁定科室信息
        List<String> deptCodeLockList = query.getDataArr().stream().map(HislowLockDtl::getDeptCodeLock).distinct().collect(Collectors.toList());
        List<Dept> deptList = deptMapper.selectList(Wrappers.<Dept>query().in("his_code", deptCodeLockList));
        BusinessException.throwValidFailIf(ObjectUtil.length(deptList)==0,"未找到相关科室信息，请联系运营人员检查");
        BusinessException.throwValidFailIf(deptList.size() != deptCodeLockList.size(),"科室信息缺失，请联系运营人员检查");
        Map<String,Dept> deptByHisCode = deptList.stream().collect(Collectors.toMap(item -> item.getHisCode(), item -> item));

        // 每个明细可使用的商品列表，一对多
        List<String> refKeyList = query.getDataArr().stream().map(HislowLockDtl::getRefKey).distinct().collect(Collectors.toList());
        Map<String,List<StockDeptLockLog>> lockGroupMatrIdAndRefKey = stockDeptLockLogService.list(Wrappers.<StockDeptLockLog>query().in("ref_key",refKeyList))
                .stream().collect(Collectors.groupingBy(item  -> item.getRefKey() +"__"+item.getMatrId()));
        ;

        for(HislowLockDtl dtl : query.getDataArr()) {
            if (matrMapByHrpCode.get(dtl.getMatrCode()) == null) {
                BusinessException.throwValidFail("未找到相关商品,商品编码[%s]",dtl.getMatrCode());
            }
            // 使用商品
            dtl.setMatrId(matrMapByHrpCode.get(dtl.getMatrCode()).getId());
            // 填充科室id
            dtl.setDeptIdLock(deptByHisCode.get(dtl.getDeptCodeLock()).getId());
            if (lockGroupMatrIdAndRefKey.containsKey(dtl.getRefKey() +"__"+dtl.getMatrId())) {
                BusinessException.throwValidFail("该单据已存在相关商品锁定信息，请先解锁,关联单据[%s],商品编码[%s],锁定时间[%s]",
                        dtl.getRefKey(),
                        dtl.getMatrCode(),
                        DateUtils.format(lockGroupMatrIdAndRefKey.get(dtl.getRefKey() +"__"+dtl.getMatrId()).get(0).getLockTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2)
                );
            }
        }

        QueryWrapper<StockDept> wrapper = Wrappers.<StockDept>query();
        wrapper.gt("qty", 0);
        wrapper.in("matr_id", matrList.stream().map(Matr::getId).collect(Collectors.toList()));
        List<StockDept> stockDeptList = baseMapper.listWithQty(wrapper);
        BusinessException.throwValidFailIf(ObjectUtil.length(stockDeptList)==0,"未找到可用库存");
        Map<String,List<StockDept>> stockDeptByDeptId = stockDeptList.stream().collect(Collectors.groupingBy(item -> item.getDeptId()));

        List<StockDept> stockDeptFindList;
        StockDept stockDeptFindOne;
        List<String> stockIdChange = new ArrayList<>();
        StockDeptLockLog lockLog;
        List<StockDeptLockLog> lockLogSave = new ArrayList<>();
        Date nowTime = DateUtils.now();

        for(HislowLockDtl dtl : query.getDataArr()) {
            if (stockDeptByDeptId.get(dtl.getDeptIdLock()) == null) {
                BusinessException.throwValidFail("未找到该科室相关库存,科室编码[%s], 商品编码[%s]",dtl.getDeptCodeLock(),dtl.getMatrCode());
            }
            stockDeptFindList = stockDeptByDeptId.get(dtl.getDeptIdLock()).stream().filter(tmp -> tmp.getMatrId().equals(dtl.getMatrId())).collect(Collectors.toList());
            if (ObjectUtil.length(stockDeptFindList) == 0 ) {
                BusinessException.throwValidFail("未找到相关库存,商品编码[%s]",dtl.getMatrCode());
            }
            if (ObjectUtil.length(stockDeptFindList) > 1 ) {
                BusinessException.throwValidFail("该科室该三级库库存找到多个，请联系运营人员检查,科室编码[%s], 商品编码[%s]",dtl.getDeptCodeLock(),dtl.getMatrCode());
            }
            stockDeptFindOne = stockDeptFindList.get(0);
            if (stockDeptFindOne.getQtyReal() < dtl.getQty()) {
                BusinessException.throwValidFail("该科室该三级库库存不足，科室编码[%s], 商品编码[%s],可用数量{%s},需锁定数量{%s}",
                        dtl.getDeptCodeLock(),
                        dtl.getMatrCode(),
                        stockDeptFindOne.getQtyReal(),
                        dtl.getQty()
                );
            }

            stockDeptFindOne.setLockQty(stockDeptFindOne.getLockQty() + dtl.getQty());
            stockDeptFindOne.setQtyReal(stockDeptFindOne.getQty() - stockDeptFindOne.getLockQty());
            stockIdChange.add(stockDeptFindOne.getId());

            lockLog = new StockDeptLockLog();
            lockLog.setRefKey(dtl.getRefKey())
                    .setMatrId(stockDeptFindOne.getMatrId())
                    .setStockId(stockDeptFindOne.getId())
                    .setLockQty(dtl.getQty())
                    .setLockComment("低耗锁定")
                    .setLockTime(nowTime)
            ;
            lockLogSave.add(lockLog);
        }

        List<StockDept> stockChange = stockDeptList.stream().filter(item -> stockIdChange.contains(item.getId())).collect(Collectors.toList());
        if (ObjectUtil.length(stockChange) > 0) {
            this.updateBatchById(stockChange);
        }
        if (ObjectUtil.length(lockLogSave) > 0) {
            stockDeptLockLogService.saveBatch(lockLogSave);
        }
    }


    /**
     * @description: 锁定库存
     * @author: Tai
     * @date: 2024/10/22 09:55
     **/
    /**
     * @description: 查询库存列表
     * @author: Tai
     * @date: 2024/10/22 09:55
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unlock(HislowUnlock query) {
        List<String> matrCodeList = query.getDataArr().stream().map(HislowUnlockDtl::getMatrCode).distinct().collect(Collectors.toList());
        List<Matr> matrList = mapper.selectList(
                Wrappers.<Matr>query()
                        .in(ObjectUtil.length(matrCodeList) > 0,"ifnull(hrp_code,'')",matrCodeList)
        );
        BusinessException.throwValidFailIf(ObjectUtil.length(matrList)==0,"未找到相关商品");

        HislowUnlockDtl unlockDtlTop = query.getDataArr().get(0);
        List<String> refKeyList = query.getDataArr().stream().map(HislowUnlockDtl::getRefKey).distinct().collect(Collectors.toList());
        List<StockDeptLockLog> logList = stockDeptLockLogService.list(Wrappers.<StockDeptLockLog>query().in("ref_key",refKeyList));
        BusinessException.throwValidFailIf(ObjectUtil.length(logList) == 0,"未找到相关锁定信息");

        List<StockDeptLockLog> logErrList = logList.stream().filter(item -> !item.getRefKey().equals(unlockDtlTop.getRefKey())).collect(Collectors.toList());
        if (ObjectUtil.length(logErrList) > 0) {
            BusinessException.throwValidFail("已锁定单据[%s]与传入单据[%s]不一致",logErrList.get(0).getRefKey(),unlockDtlTop.getRefKey());
        }

        List<String> stockIdList = logList.stream().map(StockDeptLockLog::getStockId).distinct().collect(Collectors.toList());
        List<StockDept> stockDeptList = this.list(Wrappers.<StockDept>query().in("id", stockIdList));
        BusinessException.throwValidFailIf(ObjectUtil.length(stockDeptList) == 0,"未找到相关科室库存信息");
        Map<String,StockDept> mapGroupById = stockDeptList.stream().collect(Collectors.toMap(StockDept::getId, item -> item));

        Map<String,Matr> matrMapByHrpCode = matrList.stream().collect(Collectors.toMap(item -> item.getHrpCode(), item -> item));
        for(HislowUnlockDtl dtl : query.getDataArr()) {
            if (matrMapByHrpCode.get(dtl.getMatrCode()) == null) {
                BusinessException.throwValidFail("未找到相关商品,商品编码[%s]",dtl.getMatrCode());
            }
            // 使用商品
            dtl.setMatrId(matrMapByHrpCode.get(dtl.getMatrCode()).getId());
        }

        List<StockDeptLockLog> logListFind;
        StockDeptLockLog logFind;
        StockDept stockFind;
        Date nowTime = DateUtils.now();
        List<String> logRemoveIdList= new ArrayList<>();
        List<String> stockUpdateIdList= new ArrayList<>();
        List<StockDeptLockLogHistory> logHistoryList = new ArrayList<>();
        StockDeptLockLogHistory logHistory;
        for(HislowUnlockDtl dtl : query.getDataArr()) {
            logListFind = logList.stream().filter(log -> log.getRefKey().equals(dtl.getRefKey()) && log.getMatrId().equals(dtl.getMatrId())).collect(Collectors.toList());
            if (ObjectUtil.length(logListFind) == 0 ) {
                BusinessException.throwValidFail("未找到锁定信息,关联单号[%s],商品编码[%s]",dtl.getRefKey(),dtl.getMatrCode());
            }
            if (ObjectUtil.length(logListFind) > 1 ) {
                BusinessException.throwValidFail("同一个商品找到多个锁定信息,关联单号[%s],商品编码[%s],锁定记录[%s]",dtl.getRefKey(),dtl.getMatrCode(),logListFind.size());
            }
            logFind = logListFind.get(0);
            if (!mapGroupById.containsKey(logFind.getStockId()) ) {
                BusinessException.throwValidFail("未找到库存记录,关联单号[%s],商品编码[%s]",dtl.getRefKey(),dtl.getMatrCode());
            }
            stockFind = mapGroupById.get(logFind.getStockId());
            if ( stockFind.getLockQty() < logFind.getLockQty() ) {
                BusinessException.throwValidFail(
                        "库存锁定数量不足,关联单号[%s],商品编码[%s],需解锁数量[%s],库存当前锁定数量[%s]",
                        dtl.getRefKey(),
                        dtl.getMatrCode(),
                        logFind.getLockQty(),
                        stockFind.getLockQty()
                );
            }
            stockFind.setLockQty(stockFind.getLockQty() - logFind.getLockQty());
            stockUpdateIdList.add(stockFind.getId());

            logHistory = new StockDeptLockLogHistory();
            BeanUtils.copyProperties(logFind, logHistory);
            logHistory.setUnlockQty(logFind.getLockQty()).setUnlockTime(nowTime).setUnlockRemark("解锁接口调用解锁");;
            logHistoryList.add(logHistory);
            logRemoveIdList.add(logFind.getId());
        }

        List<StockDept> stockChange = stockDeptList.stream().filter(item -> stockUpdateIdList.contains(item.getId())).collect(Collectors.toList());
        if (ObjectUtil.length(stockChange) > 0) {
            this.updateBatchById(stockChange);
        }

        if (ObjectUtil.length(logHistoryList) > 0) {
            stockDeptLockLogHistoryService.saveBatch(logHistoryList);
            stockDeptLockLogService.removeCascadeByIds(logRemoveIdList);
        }
    }

    //批量低值计费
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void billBatch(HislowBillBatch param,boolean flagRefund) {
        List<String> matrCodeList = param.getDataArr().stream().map(HislowBillBatchDtl::getMatrCode).distinct().collect(Collectors.toList());
        List<Matr> matrList = mapper.selectList(
                Wrappers.<Matr>query()
                        .in(ObjectUtil.length(matrCodeList) > 0,"ifnull(hrp_code,'')",matrCodeList)
        );
        BusinessException.throwValidFailIf(ObjectUtil.length(matrList)==0,"未找到相关商品");

        List<String> refKeyList = param.getDataArr().stream().map(HislowBillBatchDtl::getRefKey).distinct().collect(Collectors.toList());
        List<StockDeptLockLog> logList = stockDeptLockLogService.list(Wrappers.<StockDeptLockLog>query().in("ref_key",refKeyList));
        BusinessException.throwValidFailIf(ObjectUtil.length(logList) == 0,"未找到相关锁定信息");

        HislowBillBatchDtl billBatchDtlTop = param.getDataArr().get(0);
        List<StockDeptLockLog> logErrList = logList.stream().filter(item -> !item.getRefKey().equals(billBatchDtlTop.getRefKey())).collect(Collectors.toList());
        if (ObjectUtil.length(logErrList) > 0) {
            BusinessException.throwValidFail("已锁定单据[%s]与传入计费单据[%s]不一致",logErrList.get(0).getRefKey(),billBatchDtlTop.getRefKey());
        }

        Map<String,StockDeptLockLog> lockLogMapGroupByMatrId = logList.stream().collect(Collectors.toMap(StockDeptLockLog::getMatrId, item -> item));

        List<String> stockIdList = logList.stream().map(StockDeptLockLog::getStockId).distinct().collect(Collectors.toList());
        List<StockDept> stockDeptList = this.list(Wrappers.<StockDept>query().in("id", stockIdList));
        BusinessException.throwValidFailIf(ObjectUtil.length(stockDeptList) == 0,"未找到相关科室库存信息");
        Map<String,StockDept> stockMapGroupByMatrId = stockDeptList.stream().collect(Collectors.toMap(StockDept::getMatrId, item -> item));

        logList.stream().collect(Collectors.toMap(StockDeptLockLog::getStockId, item -> item));

        Map<String,Matr> matrMapByHrpCode = matrList.stream().collect(Collectors.toMap(item -> item.getHrpCode(), item -> item));
        StockDept stockFind;
        StockDeptLockLog lockFind;
        List<StockDeptBillItem> billItemList= new ArrayList<>();
        StockDeptBillItem billItem;
        List<String> logRemoveIdList= new ArrayList<>();
        List<String> stockUpdateIdList= new ArrayList<>();
        List<StockDeptLockLogHistory> logHistoryList = new ArrayList<>();
        StockDeptLockLogHistory logHistory;
        Date nowTime = DateUtils.now();
        for(HislowBillBatchDtl dtl : param.getDataArr()) {
            if (matrMapByHrpCode.get(dtl.getMatrCode()) == null) {
                BusinessException.throwValidFail("未找到相关商品,商品编码[%s]",dtl.getMatrCode());
            }
            // 使用商品
            dtl.setMatrId(matrMapByHrpCode.get(dtl.getMatrCode()).getId());

            //对应的锁定日志
            lockFind = lockLogMapGroupByMatrId.get(dtl.getMatrId());
            BusinessException.throwValidFailIf(lockFind == null,"未找到相关锁定信息,商品编码[%s]",dtl.getMatrCode());

            //对应的库存
            stockFind= stockMapGroupByMatrId.get(dtl.getMatrId());
            BusinessException.throwValidFailIf(stockFind == null,"未找到相关库存信息,商品编码[%s]",dtl.getMatrCode());

            // 计费明细
            billItem = new StockDeptBillItem();
            BeanUtils.copyProperties(dtl, billItem);
            billItem.setMatrId(stockFind.getMatrId()).setStockId(stockFind.getId());
            billItem.setQty(lockFind.getLockQty());
            billItemList.add(billItem);

            // 解锁库存-移除锁定日志
            logHistory = new StockDeptLockLogHistory();
            BeanUtils.copyProperties(lockFind, logHistory);
            logHistory.setUnlockQty(lockFind.getLockQty()).setUnlockTime(nowTime);

            if (flagRefund) { //退费
                logHistory.setUnlockRemark("退费解锁");
                stockFind.setSkuQty(stockFind.getSkuQty() + lockFind.getLockQty());
                // 解锁库存-更新库存表锁定数量
                if ( stockFind.getLockQty() < lockFind.getLockQty() ) {
                    BusinessException.throwValidFail(
                            "退费库存锁定数量不足,关联单号[%s],商品编码[%s],需解锁数量[%s],库存当前锁定数量[%s]",
                            dtl.getRefKey(),
                            dtl.getMatrCode(),
                            lockFind.getLockQty(),
                            stockFind.getLockQty()
                    );
                }
            }else {//计费
                logHistory.setUnlockRemark("计费解锁");
                stockFind.setSkuQty(stockFind.getSkuQty() - lockFind.getLockQty());
                // 解锁库存-更新库存表锁定数量
                if ( stockFind.getLockQty() < lockFind.getLockQty() ) {
                    BusinessException.throwValidFail(
                            "计费库存锁定数量不足,关联单号[%s],商品编码[%s],需解锁数量[%s],库存当前锁定数量[%s]",
                            dtl.getRefKey(),
                            dtl.getMatrCode(),
                            lockFind.getLockQty(),
                            stockFind.getLockQty()
                    );
                }
            }
            logHistoryList.add(logHistory);
            logRemoveIdList.add(lockFind.getId());

            stockFind.setLockQty(stockFind.getLockQty() - lockFind.getLockQty());
            stockUpdateIdList.add(stockFind.getId());
        }

        //1 更新库存信息
        List<StockDept> stockChange = stockDeptList.stream().filter(item -> stockUpdateIdList.contains(item.getId())).collect(Collectors.toList());
        if (ObjectUtil.length(stockChange) > 0) {
            this.updateBatchById(stockChange);
        }

        //2 锁定日志 锁定历史日志
        if (ObjectUtil.length(logHistoryList) > 0) {
            stockDeptLockLogHistoryService.saveBatch(logHistoryList);
            stockDeptLockLogService.removeCascadeByIds(logRemoveIdList);
        }

        //3 计费明细
        stockDeptBIllItemService.saveBatch(billItemList);
    }

    //添加三级库库存
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addByTransfer(Transfer transfer, List<TransferItem> transferItems) {
        if (
                systemProperties.getFlagStockDeptAdd() == null
                || !systemProperties.getFlagStockDeptAdd()
                || GlobalConsts.MATR_BASE_TYPE_LOM.equals(transfer.getTransferType())

        ) {
            return;
        }
        List<String> matrIdList = transferItems.stream().map(TransferItem::getMatrId).distinct().collect(Collectors.toList());
        String deptId = transfer.getDeptIdTo();
        // 科室退货
        boolean isDeptReturn = GlobalConsts.TransferType.returnIn.equalsIgnoreCase(transfer.getType());
        if (isDeptReturn) {
            deptId = transfer.getDeptIdFrom();
        }
        BusinessException.throwValidFailIf(StringUtils.isBlank(deptId),"三级库库存添加失败,原因目标科室不存在,调拨单%s",transfer.getBusKey());

        synchronized (deptId) {
            List<StockDept> stockDeptList = this.list(Wrappers.<StockDept>query().eq("dept_id",deptId).in("matr_id",matrIdList));
            if (stockDeptList == null) {
                stockDeptList = new ArrayList<>();
            }
            Optional<StockDept> find;
            StockDept stockFind;
            for(TransferItem transferItem :transferItems) {
                find = stockDeptList.stream().filter(item -> item.getMatrId().equals(transferItem.getMatrId())).findFirst();
                stockFind = null;
                if (find.isPresent()) {
                    stockFind = find.get();
                }
                // 科室退货，减库存
                if (isDeptReturn) {
                    if (stockFind ==null){
                        //历史数据，之前的调拨单没有产生相关库存
                        logger.error(StrUtil.format("三级库库存缺失，科室退货已忽略减库存操作，调拨单:{}，标签码:{}",transfer.getBusKey(),transferItem.getSn()));
                        continue;
                    } else{
                        if (stockFind.getSkuQty()-stockFind.getLockQty() - transferItem.getSkuQty() < 0) {
                            //历史数据，之前的调拨单没有产生相关库存
                            logger.error(StrUtil.format("三级库库存减少出现负数，即将更改三级库库存数量为0，调拨单:{}，标签码:{}",transfer.getBusKey(),transferItem.getSn()));
                            stockFind.setSkuQty(stockFind.getSkuQty() - stockFind.getLockQty());
                        }else {
                            stockFind.setSkuQty(stockFind.getSkuQty() - transferItem.getSkuQty());
                        }
                    }
                }else {
                    if (stockFind ==null){
                        stockFind = new StockDept();
                        stockFind.setDeptId(deptId).setMatrId(transferItem.getMatrId()).setSkuQty(transferItem.getSkuQty()).setLockQty(0d);
                        stockDeptList.add(stockFind);
                    } else{
                        stockFind.setSkuQty(stockFind.getSkuQty() + transferItem.getSkuQty());
                    }
                }

            }
            this.saveOrUpdateBatch(stockDeptList);
        }
    }
}
